import type { PatchState, PatchStateConfig } from "./state.ts";
import type { Transaction } from "./transaction.ts";

export interface PluginSpec<PluginState> {
  state?: StateField<PluginState>;

  key?: PluginKey;

  filterTransaction?: (tr: Transaction, state: PatchState) => boolean;

  /**
   * 使用需要注意 不能永久返回一个新的事务 不然会出现死循环
   * @param transactions
   * @param oldState
   * @param newState
   */
  appendTransaction?: (
    transactions: Transaction[],
    oldState: PatchState,
    newState: PatchState,
  ) => Transaction | null | undefined;

  [key: string]: any;
}
/*
插件类入口
*/
export class Plugin<PluginState = any> {
  spec: PluginSpec<PluginState>;
  constructor(
    spec: PluginSpec<PluginState>,
  ) {
    this.key = spec.key ? spec.key.key : createKey("plugin");
    this.spec = spec;
  }

  /// @internal
  key: string;

  /// 获取state对应的key值
  getState(state: PatchState): PluginState | undefined {
    return (state as any)[this.key];
  }
}

export interface StateField<T> {
  init: (config: PatchStateConfig, instance: PatchState) => T;

  apply: (
    tr: Transaction,
    value: T,
    oldState: PatchState,
    newState: PatchState,
  ) => T;

  toJSON?: (value: T) => any;

  fromJSON?: (config: PatchStateConfig, value: any, state: PatchState) => T;
}

const keys = Object.create(null);

function createKey(name: string) {
  if (name in keys) return name + "$" + ++keys[name];
  keys[name] = 0;
  return name + "$";
}

/*
插件key 实例
*/
export class PluginKey<PluginState = any> {
  //唯一标识
  key: string;

  constructor(name = "key") {
    this.key = createKey(name);
  }

  //从给定的配置中获取该插件
  get(state: PatchState): Plugin<PluginState> | undefined {
    return state.config.pluginsByKey[this.key];
  }

  /// 从给定的编辑器状态中获取该插件的状态
  getState(state: PatchState): PluginState | undefined {
    return (state as any)[this.key];
  }
}
